import { h,defineComponent,ref ,watch} from 'vue'
import {Cascader} from 'ant-design-vue';
import { useVModel } from '@vueuse/core'
import {arrFind, findParentList} from "@/utils";
import {uniq} from 'lodash'
import useRemoteOptions from "@/hook/remoteOptions";
import { Form } from 'ant-design-vue'
import ajax from "@/utils/ajax";
import {cloneDeep} from "lodash";
import {useInjectFormContext} from "@/components/form/context";
import {br} from "../../dist/assets/@vue.87afd1fa";
export default defineComponent({
    name: "ExCascader",
    props:{
        value:[String,Number,Array],
        options:Array,
        remote:Object,
        loadRemote:Object,
        cascaderValue:{
            type:Array,
            default:[]
        },
        single:Boolean,
        alwayLoad: Boolean,
    },
    setup(props,ctx){
        const formItemContext = Form.useInjectFormItemContext();
        const value = useVModel(props,'value',ctx.emit)
        const options  = useVModel(props,'options',ctx.emit)
        const {remoteOptionsDebounce,remoteOptions} = useRemoteOptions(props,options)
        const fieldNames = ctx.attrs.fieldNames || { label: 'label', value: 'value', children: 'children',pid: 'pid' }
        const cascaderValue = useVModel(props,'cascaderValue',ctx.emit)
        let form = useInjectFormContext()

        function updateValue(val){

            if(val === undefined){
                value.value = ctx.attrs.multiple?[]:null
            }else{
                let emitValue = cloneDeep(val)
                if(ctx.attrs.multiple){
                    value.value = convertToValue(emitValue)
                }else{
                    value.value = emitValue.pop()
                }
            }

            formItemContext.onFieldChange()
        }
        setupLoadOptions()
        function setupLoadOptions(){
            if(props.single){
                remoteOptions(value.value).then((options)=>{
                    if(props.loadRemote){
                        initLoadOptions()
                    }else{
                        cascaderValue.value = convertToCascader(value.value)
                    }
                })
            }else{
                remoteOptions().then(()=>{
                    if(props.loadRemote){
                        initLoadOptions()
                    }
                })
            }
        }
        function initLoadOptions(){
            const cloneValue = cloneDeep(cascaderValue.value)
            if(ctx.attrs.multiple){
                cloneValue.forEach(item=>{
                    loadBackDisplay(item,options.value)
                })
            }else{
                loadBackDisplay(cloneValue,options.value)
            }
        }
        async function loadBackDisplay(values,findOptions,targetOption=null){
            let cloneValue = [...values]
            for (const item of values) {
                let find = arrFind(findOptions,fieldNames.value,item,-1,fieldNames.children)
                if(find){
                    targetOption = find
                    cloneValue.shift()
                }else if(targetOption){
                    findOptions = await loadOptions(targetOption)
                    if(findOptions){
                        loadBackDisplay(cloneValue,findOptions,targetOption)
                        break
                    }
                }
            }
        }
        function convertToValue(selected){

            let arr = []
            selected.forEach(val=>{
                const endValue = val.pop()
                if(ctx.attrs.changeOnSelect){
                    arr.push(endValue)
                }else{
                    arr = arr.concat(valueCollection(endValue))
                }
            })
            return uniq(arr)
        }
        function valueCollection(search){
            const arr = [search]
            const find = arrFind(props.options,fieldNames.value,search,-1,fieldNames.children)
            if(find && find[fieldNames.children]){
                find[fieldNames.children].forEach(item=>{
                    recursionFind(item,arr)
                })
            }else{
                return [search]
            }
            return arr
        }
        function recursionFind(findItem,arr = []){
            arr.push(findItem[fieldNames.value])
            if(findItem[fieldNames.children]){
                findItem[fieldNames.children].forEach(item=>{
                    recursionFind(item,arr)
                })
            }
            return arr
        }
        function loadOptions(targetOption){
            return new Promise((resolve)=>{
                if(!targetOption.hasOwnProperty('loading') || props.alwayLoad){
                    targetOption.loading = true;
                    let config = {...props.loadRemote}
                    config.data.search = targetOption[fieldNames.value]
                    if(form){
                        config.data.data = form.submitData()
                    }
                    ajax(config).then(res=>{
                        targetOption.loading = false;
                        targetOption[fieldNames.children] = res.data
                        options.value = [...options.value]
                        resolve(res.data)
                    })
                }else{
                    resolve()
                }
            })
        }
        function convertToCascader(selected){
            if(!Array.isArray(selected)){
                if(selected){
                    selected = [selected]
                }else{
                    selected = []
                }

            }
            const formatValue = []
            selected.forEach(val=>{
                formatValue.push(
                    findParentList(options.value,val,fieldNames.value,fieldNames.pid,fieldNames.children).map(item=>{
                        return item[fieldNames.value]
                    })
                )
            })
            if(!ctx.attrs.multiple && !ctx.attrs.changeOnSelect){
                return formatValue.pop()
            }
            return formatValue
        }
        return {
            options,
            form,
            loadOptions,
            remoteOptionsDebounce,
            setupLoadOptions,
            remoteOptions,
            cascaderValue,
            fieldNames,
            updateValue
        }
    },
    render(ctx){
        let props = Object.assign({options:this.options},ctx.$attrs,{
            value:ctx.cascaderValue,
            "onUpdate:value":value=>{
                ctx.cascaderValue = value
                this.updateValue(value)
            }
        })
        if(this.remote){
            props.onSearch = (value)=>{
                this.remoteOptionsDebounce(value)
            }
            props.onDropdownVisibleChange = (open)=>{
                if(open){
                    this.setupLoadOptions()
                }
            }
        }
        if(this.loadRemote){
            props.loadData = selectedOptions =>{
                const targetOption = selectedOptions[selectedOptions.length - 1];
                this.loadOptions(targetOption)
            }
        }
        return h(Cascader, props, ctx.$slots)
    }
})